/**
 * @author BelovedLYC
 * @fileoverview 语音输入组件，提供类似微信的语音消息录制体验
 *
 * @component VoiceInput
 * @description 提供完整的语音消息录制功能，包括按住说话、上滑取消、录音波形显示、
 * 预览模式、立即发送等功能。消息发送后会立即在界面上显示带加载状态的消息，
 * 后台上传完成后自动更新状态。
 *
 * @example
 * ```tsx
 * <VoiceInput
 *   sessionId="12345"
 *   sessionType={ChatSession.PRIVATE}
 *   visible={voiceMode}
 *   onClose={() => setVoiceMode(false)}
 * />
 * ```
 *
 * @note 使用此组件需要配合AudioMessage组件来显示已发送的语音消息
 */

import React, { useState, useEffect, useRef } from "react";
import {
  View,
  Text,
  PanResponder,
  Animated,
  Pressable,
  Platform,
  TouchableOpacity,
} from "react-native";
import { Audio } from "expo-av";
import { Ionicons,  FontAwesome } from "@expo/vector-icons";
import styles from "./index.style";
import { uploadVoiceApi } from "@/services/api/file-upload";
import { getSnowflakeId } from "@/utils/snow-flake-utils";
import { getISODateTime } from "@/utils/time-utils";
import { MessageType, MessageStatus } from "@/types/chat-message";
import { SessionType } from "@/types/chat-session";
import { ResponseCode } from "@/types/api-common";
import {useUserProfileState} from "@/hooks/user/user-profile";
import {useChatMessageActions} from "@/hooks/chat/chat-message";
import {useChatSessionActions} from "@/hooks/chat/chat-session";
import {useStompSend} from "@/hooks/stomp/stomp-send";

/** 最大录音时长（秒） */
const MAX_RECORDING_DURATION = 60;
/** 最小录音时长（秒），低于此值将提示"说话时间太短" */
const MIN_RECORDING_DURATION = 1;
/**
 * 

 * @interface VoiceInputProps
 * @property {string} sessionId - 会话ID，用于发送消息
 * @property {SessionType} sessionType - 会话类型（私聊/群聊）
 * @property {boolean} visible - 组件是否可见
 * @property {function} onClose - 关闭组件的回调函数
 */
interface VoiceInputProps {
  sessionId: string;
  sessionType: SessionType;
  visible: boolean;
  onClose: () => void;
}

/**
 * 语音输入组件
 *
 * @remarks
 * 组件有三种主要状态：
 * 1. 待录制状态：显示"按住说话"按钮
 * 2. 录制状态：显示波形、时长和上滑取消提示
 * 3. 预览状态：显示播放/暂停控制和发送/重录按钮
 *
 * 录音完成后进入预览模式，用户可以听取录音内容，然后选择发送或重录。
 * 语音消息发送时会立即显示在聊天界面，带有加载状态，上传完成后自动更新。
 */
export default function VoiceInput({
  sessionId,
  sessionType,
  visible,
  onClose,
}: VoiceInputProps) {
  /** 是否正在录音 */
  const [isRecording, setIsRecording] = useState(false);
  /** 录音对象 */
  const [recording, setRecording] = useState<Audio.Recording | null>(null);
  /** 录音时长（秒） */
  const [recordingDuration, setRecordingDuration] = useState(0);
  /** 录音文件URI */
  const [audioUri, setAudioUri] = useState<string | null>(null);
  /** 是否取消录音（上滑取消） */
  const [isCancel, setIsCancel] = useState(false);
  /** 是否正在发送录音 */
  const [isSending, setIsSending] = useState(false);
  /** 音量级别，用于动态显示波形 */
  const [volumeLevel, setVolumeLevel] = useState(0);

  /** 预览模式相关状态 */
  /** 是否处于预览模式 */
  const [isPreviewMode, setIsPreviewMode] = useState(false);
  /** 是否正在播放预览 */
  const [isPlaying, setIsPlaying] = useState(false);
  /** 预览播放的声音对象 */
  const [previewSound, setPreviewSound] = useState<Audio.Sound | null>(null);

  // 音量动画
  /** 波形线数量 */
  const waveLinesCount = 7;
  /** 波形线动画值数组 */
  const waveLines = Array(waveLinesCount)
    .fill(0)
    .map((_, i) => useRef(new Animated.Value(5)).current);

  /**
   * 滑动手势设置
   * - 上滑超过60像素触发取消录音
   * - 松开手指根据isCancel状态决定取消或停止录音
   */
  const panY = useRef(new Animated.Value(0)).current;
  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onMoveShouldSetPanResponder: () => true,
      onPanResponderMove: (event, gestureState) => {
        // 如果上滑超过60像素，视为取消录音
        if (gestureState.dy < -60) {
          setIsCancel(true);
        } else {
          setIsCancel(false);
        }
        // 限制上移范围
        panY.setValue(Math.max(gestureState.dy, -200));
      },
      onPanResponderRelease: (event, gestureState) => {
        panY.setValue(0);
        if (isCancel) {
          cancelRecording();
        } else {
          stopRecording();
        }
      },
      onPanResponderTerminate: () => {
        // 处理意外中断的情况
        panY.setValue(0);
        if (isRecording) {
          stopRecording();
        }
      },
    })
  ).current;

  // 计时器
  const timerRef = useRef<NodeJS.Timeout | null>(null);

  // 用户状态、消息操作、WebSocket
  const { currentUser } = useUserProfileState()
  const { addMessage, updateMessage } = useChatMessageActions();
  const { updateSession } = useChatSessionActions();
  const {sendChatMessage} = useStompSend()

  /**
   * 组件挂载时重置状态
   * 每次组件变为可见时，重置所有状态以确保干净的启动
   */
  useEffect(() => {
    if (visible) {
      // 重置状态
      setIsRecording(false);
      setRecording(null);
      setRecordingDuration(0);
      setAudioUri(null);
      setIsCancel(false);
      setIsSending(false);
    }
  }, [visible]);

  /**
   * 录音计时功能
   * 启动一个计时器来更新录音时长，超过最大时长自动停止
   */
  useEffect(() => {
    if (isRecording) {
      timerRef.current = setInterval(() => {
        setRecordingDuration((prevDuration) => {
          const newDuration = prevDuration + 1;
          if (newDuration >= MAX_RECORDING_DURATION) {
            stopRecording();
            return MAX_RECORDING_DURATION;
          }
          return newDuration;
        });
      }, 1000);
    } else {
      if (timerRef.current) {
        clearInterval(timerRef.current);
        timerRef.current = null;
      }
    }

    return () => {
      if (timerRef.current) {
        clearInterval(timerRef.current);
        timerRef.current = null;
      }
    };
  }, [isRecording]);

  /**
   * 音量动画效果
   * 根据音量大小动态调整波形高度，并实现波动效果
   */
  useEffect(() => {
    if (isRecording) {
      const animateWaves = () => {
        waveLines.forEach((line, index) => {
          // 为中间的线条设置更高的值，形成一个波峰
          let baseHeight = 5;
          let amplitudeMultiplier = 1.0;

          // 根据索引设置基础高度，使中间的线条更高
          if (index === Math.floor(waveLinesCount / 2)) {
            baseHeight = 10;
            amplitudeMultiplier = 1.2;
          } else if (
            index === Math.floor(waveLinesCount / 2) - 1 ||
            index === Math.floor(waveLinesCount / 2) + 1
          ) {
            baseHeight = 8;
            amplitudeMultiplier = 1.1;
          }

          const randomHeight =
            baseHeight +
            Math.random() * 20 * (volumeLevel + 0.2) * amplitudeMultiplier;

          Animated.timing(line, {
            toValue: randomHeight,
            duration: 300 + index * 50,
            useNativeDriver: false,
          }).start();
        });
      };

      const interval = setInterval(animateWaves, 500);
      return () => clearInterval(interval);
    }
  }, [isRecording, volumeLevel]);

  /**
   * 开始录音
   * 请求麦克风权限，设置音频模式，创建新的录音对象并开始录制
   */
  async function startRecording() {
    try {
      // 请求音频权限
      const permissionResponse = await Audio.requestPermissionsAsync();
      if (permissionResponse.status !== "granted") {
        alert("需要麦克风权限才能录音");
        return;
      }

      // 设置音频模式
      await Audio.setAudioModeAsync({
        allowsRecordingIOS: true,
        playsInSilentModeIOS: true,
        staysActiveInBackground: true,
        interruptionModeIOS: 1, // Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX
        interruptionModeAndroid: 1, // Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX
      });

      // 创建新录音
      const newRecording = new Audio.Recording();

      // 准备录音
      await newRecording.prepareToRecordAsync(
        Audio.RecordingOptionsPresets.HIGH_QUALITY
      );

      // 开始音量监测
      newRecording.setOnRecordingStatusUpdate((status) => {
        if (status.isRecording) {
          setVolumeLevel(status.metering || 0);
        }
      });

      // 开始录音
      await newRecording.startAsync();
      setRecording(newRecording);
      setIsRecording(true);
      setRecordingDuration(0);
      setIsCancel(false);
    } catch (error) {
      console.error("Failed to start recording:", error);
      alert("录音失败，请检查麦克风权限");
      setIsRecording(false);
    }
  }

  /**
   * 停止录音
   * 停止并保存录音，检查最小时长，符合要求则进入预览模式
   */
  async function stopRecording() {
    if (!recording) {
      setIsRecording(false);
      return;
    }

    try {
      // 停止录音
      await recording.stopAndUnloadAsync();

      // 重置音频模式
      await Audio.setAudioModeAsync({
        allowsRecordingIOS: false,
        playsInSilentModeIOS: true,
      });

      // 获取录音URI
      const uri = recording.getURI();

      // 设置状态
      setAudioUri(uri);
      setIsRecording(false);

      // 如果时长太短，则提示并取消
      if (recordingDuration < MIN_RECORDING_DURATION) {
        alert("说话时间太短");
        setRecording(null);
        setAudioUri(null);
        return;
      }

      // 进入预览模式
      setIsPreviewMode(true);
    } catch (error) {
      console.error("Failed to stop recording:", error);
      alert("录音保存失败");
      setIsRecording(false);
    }
  }

  /**
   * 播放预览
   * 播放或暂停录音预览，控制播放状态
   */
  async function playPreview() {
    if (!audioUri) return;

    try {
      if (isPlaying && previewSound) {
        // 暂停
        await previewSound.pauseAsync();
        setIsPlaying(false);
      } else {
        // 播放
        // 如果已有声音对象，先释放
        if (previewSound) {
          await previewSound.unloadAsync();
        }

        // 设置音频模式
        await Audio.setAudioModeAsync({
          allowsRecordingIOS: false,
          playsInSilentModeIOS: true,
          staysActiveInBackground: true,
          interruptionModeIOS: 1,
          interruptionModeAndroid: 1,
        });

        // 创建新的声音对象
        const { sound } = await Audio.Sound.createAsync(
          { uri: audioUri },
          { shouldPlay: true },
          onPlaybackStatusUpdate
        );

        setPreviewSound(sound);
        setIsPlaying(true);
      }
    } catch (error) {
      console.error("Failed to play preview:", error);
    }
  }

  /**
   * 播放状态更新回调
   * 监听播放状态变化，处理播放结束事件
   */
  const onPlaybackStatusUpdate = (status) => {
    if (status.isLoaded) {
      setIsPlaying(status.isPlaying);

      // 播放结束时重置
      if (
        status.didJustFinish ||
        (status.positionMillis > 0 &&
          status.positionMillis === status.durationMillis)
      ) {
        setIsPlaying(false);

        if (previewSound) {
          previewSound.setPositionAsync(0);
        }
      }
    }
  };

  /**
   * 发送录音预览
   * 停止预览播放，立即关闭录音界面，然后在后台发送录音
   */
  async function sendPreview() {
    if (!audioUri) return;

    // 停止预览播放
    if (previewSound) {
      await previewSound.unloadAsync();
      setPreviewSound(null);
      setIsPlaying(false);
    }

    // 保存当前的音频URI和录音时长
    const currentAudioUri = audioUri;
    const currentDuration = recordingDuration;

    // 立即退出预览模式并关闭录音界面，返回到聊天界面
    setIsPreviewMode(false);
    onClose();

    // 在后台发送录音
    await sendVoiceMessage(currentAudioUri, currentDuration);
  }

  /**
   * 取消预览
   * 停止预览播放，清理录音，退出预览模式
   */
  async function cancelPreview() {
    // 停止预览播放
    if (previewSound) {
      await previewSound.unloadAsync();
      setPreviewSound(null);
      setIsPlaying(false);
    }

    // 清理录音
    setAudioUri(null);
    setRecording(null);

    // 退出预览模式
    setIsPreviewMode(false);
  }

  /**
   * 组件卸载时释放资源
   */
  useEffect(() => {
    return () => {
      if (previewSound) {
        previewSound.unloadAsync();
      }
    };
  }, [previewSound]);

  /**
   * 取消录音
   * 停止并清理录音，重置状态
   */
  async function cancelRecording() {
    if (!recording) {
      setIsRecording(false);
      return;
    }

    try {
      await recording.stopAndUnloadAsync();
      await Audio.setAudioModeAsync({
        allowsRecordingIOS: false,
        playsInSilentModeIOS: true,
      });
      setIsRecording(false);
      setRecording(null);
      setAudioUri(null);
    } catch (error) {
      console.error("Failed to cancel recording:", error);
      setIsRecording(false);
    }
  }

  /**
   * 发送语音消息
   * 采用"先显示后上传"的策略，先创建消息显示在界面上，
   * 然后异步上传文件，上传成功后更新消息状态
   *
   * @param {string} uri - 录音文件URI
   * @param {number} duration - 录音时长（秒）
   */
  async function sendVoiceMessage(uri: string, duration: number) {
    //上传逻辑
    try {
      setIsSending(true);
      // 生成唯一消息ID
      const messageId = getSnowflakeId();
      const currentTime = getISODateTime(new Date());
      const ownerId = String(currentUser.id);

      const msg = {
        messageId: messageId,
        messageType: MessageType.VOICE,
        content: {
          // 临时payload，上传成功后会更新
          fileUrl: uri,
          fileName: `voice_${Date.now()}.m4a`,
          fileInfo: {
            duration: duration,
            bitRate: 0,
            sampleRate: 0,
            audioChannel: 0,
          },
        },
        revokeStatus: false,
        system: false,
        createTime: Date.now(),
        user: {
          id: String(currentUser.id),
          name: currentUser.nickname,
          avatar: currentUser.avatar,
          updateTime: Date.now(),
        },
        sessionId,
        sessionType,
        status: MessageStatus.SENDING,
        ownerId: ownerId,
      };

      await addMessage(msg);

      // Update session with last message
      await updateSession({
        sessionId: sessionId,
        lastMessageId: msg.messageId,
        lastMessage: `【语音：${duration}秒】`,
      });

      const formData = new FormData();
      const fileName = `voice_${Date.now()}.m4a`;
      formData.append("file", {
        uri: Platform.OS === "ios" ? uri.replace("file://", "") : uri,
        name: fileName,
        type: "audio/m4a",
      } as any);

      // 上传音频文件
      const response = await uploadVoiceApi(formData);
      if (response.data.code === ResponseCode.SUCCESS) {
        const audioData = response.data.data;
        // 更新消息对象的payload和状态
        const updatedMsg = {
          messageId: messageId,
          ownerId: ownerId,
          content: {
            ...audioData,
            duration: duration,
          },
        };

        // 更新消息在本地数据库
        await updateMessage(updatedMsg);

        // 通过WebSocket发送消息
        sendChatMessage({
          user: {
            id: currentUser.id,
            name: currentUser.nickname,
            avatar: currentUser.avatar,
            updateTime: currentUser.updateTime
          },
          messageId: messageId,
          content: updatedMsg.content,
          messageType: msg.messageType,
          sessionId,
          sessionType,
          createTime: Date.now()
        })

        // 清理录音状态
        setRecording(null);
        setAudioUri(null);
        setRecordingDuration(0);
      } else {
        // 更新消息状态为失败
        const failedMsg = {
          ...msg,
          status: MessageStatus.FAILED,
          ownerId: ownerId,
        };

        await addMessage(failedMsg);
        console.error("语音上传失败");
      }
    } catch (error) {
      console.error("Failed to send voice message:", error);
      // 不显示提示，因为消息已经显示在界面上带有失败状态
    } finally {
      setIsSending(false);
    }
  }

  /**
   * 渲染录音波形
   * 显示动态波形可视化效果
   */
  const renderVoiceWaves = () => {
    return (
      <View style={styles.voiceWaveContainer}>
        {waveLines.map((line, index) => (
          <Animated.View
            key={index}
            style={[
              styles.voiceWaveLine,
              {
                height: line,
                backgroundColor: index % 2 === 0 ? "#1AAD19" : "#34C759",
                width: index === Math.floor(waveLinesCount / 2) ? 6 : 4,
              },
            ]}
          />
        ))}
      </View>
    );
  };

  /**
   * 格式化时间为 mm:ss 格式
   * @param {number} seconds - 秒数
   * @returns {string} 格式化后的时间字符串
   */
  const formatTime = (seconds: number) => {
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins.toString().padStart(2, "0")}:${secs
      .toString()
      .padStart(2, "0")}`;
  };

  /**
   * 渲染录音状态指示器
   * 显示波形动画、录音时长和提示文本
   */
  const renderRecordingStatus = () => {
    return (
      <>
        {isRecording && (
          <Text
            style={[
              styles.cancelHint,
              { color: isCancel ? "#FF3B30" : "#FFFFFF" },
            ]}
          >
            {isCancel ? "松开手指，取消发送" : "上滑取消"}
          </Text>
        )}

        {isRecording && !isCancel && (
          <Animated.View
            style={[
              styles.recordingContainer,
              {
                transform: [{ translateY: panY }],
              },
            ]}
          >
            <Ionicons
              name="mic"
              size={36}
              color="#1AAD19"
              style={styles.micIcon}
            />
            <View style={styles.voiceWaveContainer}>{renderVoiceWaves()}</View>
            <Text style={styles.timerText}>
              {formatTime(recordingDuration)}
            </Text>
            <Text style={styles.releaseText}>松开 结束</Text>
          </Animated.View>
        )}

        {isRecording && isCancel && (
          <Animated.View
            style={[
              styles.cancelContainer,
              {
                transform: [{ translateY: panY }],
              },
            ]}
          >
            <View style={styles.cancelIconContainer}>
              <Ionicons name="trash" size={32} color="#D43030" />
            </View>
            <Text style={styles.cancelText}>松开手指，取消发送</Text>
          </Animated.View>
        )}
      </>
    );
  };

  /**
   * 渲染预览模式
   * 显示播放控制和操作按钮（重录/发送）
   */
  const renderPreviewMode = () => {
    if (!isPreviewMode || !audioUri) return null;

    return (
      <View style={styles.previewContainer}>
        {/* 播放/暂停按钮 */}
        <TouchableOpacity
          style={styles.previewPlayButton}
          onPress={playPreview}
        >
          <FontAwesome
            name={isPlaying ? "pause" : "play"}
            size={14}
            color="#1AAD19"
          />
        </TouchableOpacity>

        {/* 时长显示 */}
        <Text style={styles.previewDuration}>
          语音消息 ({recordingDuration}秒)
        </Text>

        {/* 操作按钮 */}
        <View style={styles.previewActions}>
          <TouchableOpacity style={styles.actionButton} onPress={cancelPreview}>
            <Text style={[styles.actionText, styles.cancelActionText]}>
              重录
            </Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.actionButton} onPress={sendPreview}>
            <Text style={styles.actionText}>发送</Text>
          </TouchableOpacity>
        </View>
      </View>
    );
  };

  return (
    <View style={styles.container}>
      {/* 预览模式 */}
      {isPreviewMode ? (
        renderPreviewMode()
      ) : (
        /* 按住说话按钮 */
        <Pressable
          style={({ pressed }) => [
            styles.button,
            pressed && styles.buttonPressed,
          ]}
          onPressIn={startRecording}
          onPressOut={isCancel ? cancelRecording : stopRecording}
          {...panResponder.panHandlers}
        >
          <Text style={styles.buttonText}>
            {isRecording ? (isCancel ? "松开取消" : "松开结束") : "按住说话"}
          </Text>
        </Pressable>
      )}

      {/* 录音状态显示 */}
      {renderRecordingStatus()}
    </View>
  );
}
